package com.wds.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wds.common.utils.BeanCopyUtils;
import com.wds.common.utils.RedisCacheUtils;
import com.wds.domain.JsonResult;
import com.wds.domain.dto.ArticleAddDto;
import com.wds.domain.dto.ArticleUpdateDto;
import com.wds.domain.entity.Article;
import com.wds.domain.entity.ArticleTag;
import com.wds.domain.entity.Category;
import com.wds.domain.type.SystemConstants;
import com.wds.domain.vo.*;
import com.wds.exception.CustomException;
import com.wds.mapper.ArticleMapper;
import com.wds.service.ArticleService;
import com.wds.service.ArticleTagService;
import com.wds.service.CategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 文章表(Article)表服务实现类
 *
 * @author wds
 * @since 2022-10-21 15:50:18
 */
@Service("articleService")
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {

    @Autowired
    @Lazy
    private CategoryService categoryService;


    @Autowired
    private RedisCacheUtils redisCache;

    /**
     * 查询热门文章 查询条件
     * 1.按照浏览量倒序排序，取前十
     * 2.已经发布的文章
     * 3.逻辑删除 由 mp控制
     */
    @Override
    public JsonResult<Object> hotArticleList() {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();


        queryWrapper.orderByDesc(Article::getViewCount);
        queryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL);
        Page<Article> page = page(new Page<>(1, 10), queryWrapper);
        List<HotArticleVo> result = BeanCopyUtils.copyList(page.getRecords(), HotArticleVo.class);

        // 从redis中刷新浏览量
        Map<Long, Long> viewCountMap = redisCache.getCacheLongMap("viewCountMap");
        result = result.stream().map(item -> {
            item.setViewCount(viewCountMap.get(item.getId()));
            return item;
        }).collect(Collectors.toList());

        return JsonResult.ok(result);
    }

    /**
     * 首页查询文章列表
     * 如果有，要对应分类 正式发布的文章 置顶
     *
     * @param categoryId 文章分类
     * @param pageNum    当前页
     * @param pageSize   每页展示多少条记录
     * @return Page
     */
    @Override
    public JsonResult<Object> articleList(Integer categoryId, int pageNum, int pageSize) {

        Page<Article> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Article> articleWrapper = new LambdaQueryWrapper<>();
//        正式文章
        articleWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL);
//        分类   有分类ID 且 >0
        articleWrapper.eq(categoryId != null && categoryId > 0, Article::getCategoryId, categoryId);
//        置顶
        articleWrapper.orderByDesc(Article::getIsTop);


        Page<Article> articlePage = page(page, articleWrapper);

        List<ArticleListVo> articleListVos = BeanCopyUtils.copyList(articlePage.getRecords(), ArticleListVo.class);
        // 封装分类名称

        articleListVos = articleListVos.stream().map(item -> {
            Category category = categoryService.getById(item.getCategoryId());
            item.setCategoryName(category.getName());
            return item;
        }).collect(Collectors.toList());
        PageVo pageVo = new PageVo();
        pageVo.setRows(articleListVos);
        pageVo.setTotal(page.getTotal());

        // 从redis中刷新浏览量

        List<?> rows = pageVo.getRows();
        rows = rows.stream().map(item -> {
            ArticleListVo vo = (ArticleListVo) item;
            Map<Long, Long> viewCountMap = redisCache.getCacheLongMap("viewCountMap");
            vo.setViewCount(viewCountMap.get(vo.getId()));
            return vo;
        }).collect(Collectors.toList());
        pageVo.setRows(rows);

        return JsonResult.ok(pageVo);
    }

    /**
     * 获取文章详情
     *
     * @param articleId 文章id
     * @return vo  如果没有就是null
     */
    @Override
    public JsonResult<Object> getArticleDetail(Long articleId) {

        Article article = getById(articleId);
        if (article == null) {
            throw new CustomException("没有检索到对应文章，请检查查询条件。期望的文章ID:" + articleId);
        }
        Category articleCategory = categoryService.getById(article.getCategoryId());

        // 封装分类名称
        ArticleDetailVo articleDetailVo = BeanCopyUtils.copy(article, ArticleDetailVo.class);
        articleDetailVo.setCategoryName(articleCategory.getName());

        // 从redis中刷新浏览量
        Map<Long, Long> map = redisCache.getCacheLongMap("viewCountMap");
        Long count = map.get(articleDetailVo.getId());
        articleDetailVo.setViewCount(count);

        return JsonResult.ok(articleDetailVo);
    }


    /**
     * 更新redis中的浏览量
     *
     * @param articleId 文章id
     */
    @Override
    public void updateViewCount(Long articleId) {
        Map<Long, Long> map = redisCache.getCacheLongMap("viewCountMap");
//        如果缓存里没有当前文章的浏览量就设置为 1
        map.putIfAbsent(articleId, 1L);
        map.put(articleId, map.get(articleId) + 1);
        redisCache.setCacheMap("viewCountMap", map);
    }

    @Override
    public void updateViewCountToMysql(Long id, Long viewCount) {
        Article article = new Article();
        article.setId(id);
        article.setViewCount(viewCount);
        try {
            updateById(article);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    @Autowired
    private ArticleTagService articleTagService;

    @Override
    @Transactional
    public JsonResult<Object> addNewArticle(ArticleAddDto dto) {
        if (dto.getCategoryId() == null) {
            throw new CustomException("请选者一个分类");
        }
//        添加文章
        Article article = BeanCopyUtils.copy(dto, Article.class);
        save(article);
//        添加标签文章对应关系
//        构建关系
        List<Long> tagIds = dto.getTags();
        ArrayList<ArticleTag> articleTags = new ArrayList<>();
        for (Long tagId : tagIds) {
            articleTags.add(new ArticleTag(article.getId(), tagId));
        }
        articleTagService.saveArticleTags(articleTags);
        return JsonResult.ok();
    }

    @Override
    public JsonResult<Object> listAllArticle(Integer pageNum, Integer pageSize, String title, String summary) {
        if (pageNum == null) {
            pageNum = 1;
        }
        if (pageSize == null || pageSize > 40) {
            pageSize = 10;
        }
        Page<Article> articlePage = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.hasText(title), Article::getTitle, "%" + title + "%");
        queryWrapper.like(StringUtils.hasText(summary), Article::getSummary, "%" + summary + "%");

        page(articlePage, queryWrapper);
        ArticleListPageVo pageVo = new ArticleListPageVo();
        pageVo.setRows(BeanCopyUtils.copyList(articlePage.getRecords(), ArticleListVo.class));
        pageVo.setTotal(articlePage.getTotal());

        return JsonResult.ok(pageVo);
    }

    @Override
    public JsonResult<Object> queryOne(Long id) {
//        查询文章
        Article article = getById(id);
        ArticleQueryOneVo vo = BeanCopyUtils.copy(article, ArticleQueryOneVo.class);
//        查询标签
        List<ArticleTag> tags = articleTagService.listByArticleId(id);
        ArrayList<Long> tagIds = new ArrayList<>();
        for (ArticleTag tag : tags) {
            tagIds.add(tag.getTagId());
        }
        vo.setTags(tagIds);
        return JsonResult.ok(vo);
    }

    @Override
    public JsonResult<Object> updateArticle(ArticleUpdateDto articleDto) {
        if (articleDto.getId() == null) {
            throw new CustomException("修改失败,请检查ID输入！");
        }
        Article updateArticle = BeanCopyUtils.copy(articleDto, Article.class);
        boolean updateStatus = updateById(updateArticle);

        if (updateStatus) {
//            继续修改对应的标签对应内容
//            删除旧的
            ArrayList<Long> articleIds = new ArrayList<>();
            articleIds.add(articleDto.getId());
            articleTagService.removeByArticleIds(articleIds);
//            加入新的
            ArrayList<ArticleTag> articleTags = new ArrayList<>();
            for (Long tag : articleDto.getTags()) {
                articleTags.add(
                        new ArticleTag(articleDto.getId(), tag));
            }
            articleTagService.saveArticleTags(articleTags);
            return JsonResult.ok();
        } else {
            return JsonResult.fail();
        }
    }

    @Override
    public JsonResult<Object> deleteArticle(List<Long> ids) {
        boolean result = removeByIds(ids);
        if (result) {
//            删除对应的标签对应内容
            articleTagService.removeByArticleIds(ids);
            return JsonResult.ok();
        } else {
            return JsonResult.fail();
        }
    }


}

